Skip to main content

Contract Functions

To send a transaction that executes a function of a contract on a blockchain, you can use a useContractFunction hook, it works similarly to useSendTransaction. It returns a send function that we can use to call a contract function and state object.

To use useContractFunction we need to supply it with a Contract of type Contract. And a string functionName.

send function maps arguments 1 to 1 with functions of a contract and also accepts one additional argument of type TransactionOverrides.

Example

Start by declaring a contract variable with address of contract you want to call and ABI interface of a contract.

  import { utils } from 'ethers'
import { Contract } from '@ethersproject/contracts'

...

const wethInterface = new utils.Interface(WethAbi)
const wethContractAddress = '0xA243FEB70BaCF6cD77431269e68135cf470051b4'
const contract = new Contract(wethContractAddress, wethInterface)

After that you can use the hook to create send function and state object.

  const { state, send } = useContractFunction(contract, 'deposit', { transactionName: 'Wrap' })

const depositEther = (etherAmount: string) => {
send({ value: utils.parseEther(etherAmount) })
}
  const { state, send } = useContractFunction(contract, 'withdraw', { transactionName: 'Unwrap' })

const withdrawEther = (wethAmount: string) => {
send(utils.parseEther(wethAmount))
}

The code snippets above will wrap and unwrap Ether into WETH using Wrapped Ether contract respectively. Deposit function of a contract has no input arguments and instead wraps amount of ether sent to it. To send given amount of ether simply use a TransactionOverrides object. Withdraw function needs amount of ether to withdraw as a input argument.

You can add additional buffer of gas limit by setting gasLimitBufferPercentage in config or directly in transaction options, see live example below. It adds 10% of gas limit more to what is estimated by the Ethers library.

Live example

App will deposit 1 wei to Wrapped Ether contract. Connect a MetaMask wallet and switch to a test network, such as Kovan or Ropsten.

App.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { DAppProvider, useEthers, useContractFunction, Config, Goerli, Kovan, Rinkeby, Ropsten } from '@usedapp/core'
import { getDefaultProvider, utils } from 'ethers'
import { Contract } from '@ethersproject/contracts'
import { WethAbi, WETH_ADDRESSES } from './constants/Weth'
import { MetamaskConnect } from './components/MetamaskConnect'

const config: Config = {
readOnlyChainId: Goerli.chainId,
readOnlyUrls: {
[Goerli.chainId]: getDefaultProvider('goerli'),
[Kovan.chainId]: getDefaultProvider('kovan'),
[Rinkeby.chainId]: getDefaultProvider('rinkeby'),
[Ropsten.chainId]: getDefaultProvider('ropsten'),
},
}

ReactDOM.render(
<DAppProvider config={config}>
<App />
</DAppProvider>,
document.getElementById('root')
)

const WrapEtherComponent = (props: { chainId: number }) => {
const wethAddress = WETH_ADDRESSES[props.chainId]
const wethInterface = new utils.Interface(WethAbi)
const contract = new Contract(wethAddress, wethInterface) as any

const { state, send } = useContractFunction(contract, 'deposit', {
transactionName: 'Wrap',
gasLimitBufferPercentage: 10,
})
const { status } = state

const wrapEther = () => {
void send({ value: 1 })
}

return (
<div>
<button onClick={() => wrapEther()}>Wrap ether</button>
<p>Status: {status}</p>
</div>
)
}

export function App() {
const { account, chainId } = useEthers()

if (!config.readOnlyUrls[chainId]) {
return <p>Please use either Goerli, Kovan, Rinkeby or Ropsten testnet.</p>
}

return <div>{!account ? <MetamaskConnect /> : <WrapEtherComponent chainId={chainId} />}</div>
}